#include "business/recordbusiness/proto/sensor_proto.h"
#include <string.h>
#include <string>
#include <sstream>
#include "common/sensordata.h"
#include "common/common_log.h"

enum FIG_DATA_TYPE {
  ACC = 0x61,
  SPEED = 0x76,
  MOVE = 0x64
};

enum AXIS_TYPE {
  AXIS_X = 0x78,
  AXIS_Y = 0x79,
  AXIS_Z = 0x7A,
  AXIS_H = 0x68
};

#define PLC_CHAN 0x4

static uint16_t ConvertEndium(uint16_t rawvalue) {
  uint16_t ret = ((rawvalue & 0xff00) >> 8) |
                 ((rawvalue & 0x00ff) << 8);

  return ret;
}

static uint32_t ConvertEndium(uint32_t rawvalue) {
  uint32_t ret = ((rawvalue & 0xff000000) >> 24) |
                 ((rawvalue & 0x00ff0000) >> 8) |
                 ((rawvalue & 0x0000ff00) << 8) |
                 ((rawvalue & 0x000000ff) << 24);

  return ret;
}

static uint64_t ConvertEndium(uint64_t rawvalue) {
  uint64_t ret = ((rawvalue & 0xff00000000000000) >> 56) |
                 ((rawvalue & 0x00ff000000000000) >> 40) |
                 ((rawvalue & 0x0000ff0000000000) >> 24) |
                 ((rawvalue & 0x000000ff00000000) >> 8) |
                 ((rawvalue & 0x00000000ff000000) << 8) |
                 ((rawvalue & 0x0000000000ff0000) << 24) |
                 ((rawvalue & 0x000000000000ff00) << 40) |
                 ((rawvalue & 0x00000000000000ff) << 56);

  return ret;
}

static double ConvertEndium(double orivalue) {
  uint64_t rawvalue = 0;
  memcpy(&rawvalue, &orivalue, sizeof(orivalue));
  uint64_t ret = ((rawvalue & 0xff00000000000000) >> 56) |
                 ((rawvalue & 0x00ff000000000000) >> 40) |
                 ((rawvalue & 0x0000ff0000000000) >> 24) |
                 ((rawvalue & 0x000000ff00000000) >> 8) |
                 ((rawvalue & 0x00000000ff000000) << 8) |
                 ((rawvalue & 0x0000000000ff0000) << 24) |
                 ((rawvalue & 0x000000000000ff00) << 40) |
                 ((rawvalue & 0x00000000000000ff) << 56);
  double retvalue = 0;
  memcpy(&retvalue, &ret, sizeof(ret));

  return retvalue;
}

static float ConvertEndium(float orivalue) {
  uint32_t rawvalue = 0;
  memcpy(&rawvalue, &orivalue, sizeof(orivalue));
  uint32_t ret = ((rawvalue & 0xff000000) >> 24) |
                 ((rawvalue & 0x00ff0000) >> 8) |
                 ((rawvalue & 0x0000ff00) << 8) |
                 ((rawvalue & 0x000000ff) << 24);
  float retvalue = 0;
  memcpy(&retvalue, &ret, sizeof(ret));

  return retvalue;
}

SensorProtoManager::SensorProtoManager() {}

SensorProtoManager::~SensorProtoManager() {}

void SensorProtoManager::SetFigureData(const int32_t &chanIndex,
                                 figureData &dataArray, float data) {
  switch (chanIndex) {
  case 0:
    dataArray.maxValue = data;
    break;
  case 1:
    dataArray.minValue = data;
    break;
  case 2:
    dataArray.peakValue = data;
    break;
  case 3:
    dataArray.averageValue = data;
    break;
  case 4:
    dataArray.absAverageValue = data;
    break;
  case 5:
    dataArray.variance = data;
    break;
  case 6:
    dataArray.standardDeviation = data;
    break;
  case 7:
    dataArray.kurtosis = data;
    break;
  case 8:
    dataArray.margin = data;
    break;
  case 9:
    dataArray.waveFactor = data;
    break;
  case 10:
    dataArray.peakFactor = data;
    break;
  case 11:
    dataArray.pulseFactor = data;
    break;
  case 12:
    dataArray.mainFrequency = data;
    break;
  case 13:
    dataArray.mainAmp = data;
    break;
  default:
    break;
  }
}

void SensorProtoManager::SetRawData(const int32_t &chanIndex,
                                    rawData &dataArray, float data) {
  switch (chanIndex) {
  case 0:
    dataArray.rawValue.push_back(data);
    break;
  default:
    break;
  }
}

void SensorProtoManager::SetPlcData(const int32_t &chanIndex,
                                    plcData &dataArray, float data) {
  switch (chanIndex) {
  case 0:
    dataArray.yawposition = data;
    break;
  case 1:
    dataArray.yawspeed = data;
    break;
  case 2:
    dataArray.pitchAngle1 = data;
    break;
  case 3:
    dataArray.pitchAngle1Demand = data;
    break;
  case 4:
    dataArray.PitchSpeed1 = data;
    break;
  case 5:
    dataArray.GenSpeed = data;
    break;
  case 6:
    dataArray.emsRotorSpeed = data;
    break;
  case 7:
    dataArray.cnvOutRealPower = data;
    break;
  case 8:
    dataArray.gridRealPower = data;
    break;
  case 9:
    dataArray.vibx = data;
    break;
  case 10:
    dataArray.viby = data;
    break;
  case 11:
    dataArray.yawstatecode = data;
    break;
  case 12:
    dataArray.winspeed1 = data;
    break;
  case 13:
    dataArray.plcfirsterror = data;
    break;
  case 14:
    dataArray.gentorque = data;
    break;
  case 15:
    dataArray.torqueDemandFeedback = data;
    break;
  case 16:
    dataArray.mainShaftHubSideTemp = data;
    break;
  case 17:
    dataArray.mainshaftGbxTemp = data;
    break;
  case 18:
    dataArray.gbxLssTemp = data;
    break;
  case 19:
    dataArray.gbxHssTemp = data;
    break;
  case 20:
    dataArray.gbxOilTemp = data;
    break;
  case 21:
    dataArray.genShaft1Temp = data;
    break;
  case 22:
    dataArray.genShaft2Temp = data;
    break;
  case 23:
    dataArray.pchBand6 = data;
    break;
  case 24:
    dataArray.pchBand11 = data;
    break;
  default:
    break;
  }
}

int32_t SensorProtoManager::GetSensorChan(uint8_t axis, uint8_t &sensorChan) {
  if (axis == AXIS_TYPE::AXIS_X) {
    sensorChan = 0;
  } else if (axis == AXIS_TYPE::AXIS_Y) {
    sensorChan = 1;
  } else if (axis == AXIS_TYPE::AXIS_Z) {
    sensorChan = 2;
  } else {
    return -1;
  }

  return 0;
}

int32_t SensorProtoManager::GetFigDataType(uint8_t axis, uint8_t data_type) {
  int32_t figDataType = -1;

  if (data_type == FIG_DATA_TYPE::ACC) {
    if (axis == AXIS_TYPE::AXIS_X) {
      figDataType = SensorDataInfo::CHAN_ACCX;
    } else if (axis == AXIS_TYPE::AXIS_Y) {
      figDataType = SensorDataInfo::CHAN_ACCY;
    } else if (axis == AXIS_TYPE::AXIS_Z) {
      figDataType = SensorDataInfo::CHAN_ACCZ;
    }
  } else if (data_type == FIG_DATA_TYPE::MOVE) {
    if (axis == AXIS_TYPE::AXIS_X) {
      figDataType = SensorDataInfo::CHAN_MOVEX;
    } else if (axis == AXIS_TYPE::AXIS_Y) {
      figDataType = SensorDataInfo::CHAN_MOVEY;
    } else if (axis == AXIS_TYPE::AXIS_Z) {
      figDataType = SensorDataInfo::CHAN_MOVEZ;
    }
  } else if (data_type == FIG_DATA_TYPE::SPEED) {
    if (axis == AXIS_TYPE::AXIS_X) {
      figDataType = SensorDataInfo::CHAN_SPEEDX;
    } else if (axis == AXIS_TYPE::AXIS_Y) {
      figDataType = SensorDataInfo::CHAN_SPEEDY;
    } else if (axis == AXIS_TYPE::AXIS_Z) {
      figDataType = SensorDataInfo::CHAN_SPEEDZ;
    }
  }

  return figDataType;
}

int32_t SensorProtoManager::DeSerializePlcData(uint8_t *recvData,
                                               const int32_t recvSize,
                                               uint8_t *leftData,
                                               int32_t &leftSize) {
  //找到完整的一帧数据
  for (int32_t index = 0; index < recvSize; index++) {
    if (recvData[index] == 0xa5 && recvData[index + 1] == 0x5a) {
      PlcHead *head = reinterpret_cast<PlcHead *>(recvData + index);
      int32_t framelen = index + sizeof(PlcHead) +
                         ConvertEndium(head->plcDatalen) * sizeof(float);
      if (framelen > recvSize) {
        Common_Log_e("plc framelen:%d recvSize:%d\n", framelen, recvSize);
        return -1;
      }

      if (PLC_CHAN != (head->ch) || head->valid == 0) {
        Common_Log_e("not invalid plc data ch:%x, valid:%d", head->ch, head->valid);
        return -2;
      }

      int32_t listSize =
          ConvertEndium(head->plcDatalen) / (PLC_TYPE_NUM * DATA_WIDTH);
      if (listSize == 0) {
        Common_Log_e("plc list size is 0");
        return -3;
      }
      std::vector<std::map<int32_t, plcData>> plcList;
      plcList.resize(listSize);

      //解析plc数据
      for (int32_t plcIndex = 0;
           plcIndex < listSize * (PLC_TYPE_NUM * DATA_WIDTH);
           plcIndex += DATA_WIDTH) {
        int32_t cirtimes = plcIndex / (PLC_TYPE_NUM * DATA_WIDTH);
        int32_t cirIndex = plcIndex % (PLC_TYPE_NUM * DATA_WIDTH);
        int32_t typeIndex = cirIndex / (PLC_TYPE_NUM * DATA_WIDTH);
        int32_t chanIndex =
            (cirIndex % (PLC_TYPE_NUM * DATA_WIDTH)) / DATA_WIDTH;

        std::map<int32_t, plcData> &OncePlcData = plcList[cirtimes];
        float plcvalue = *((float *)(recvData + index + sizeof(PlcHead) +
                                     plcIndex * sizeof(float)));
        SetPlcData(chanIndex, OncePlcData[typeIndex], ConvertEndium(plcvalue));
      }
      std::stringstream sensorKey;
      sensorKey << std::hex << head->taskId << head->mccAddr;

      std::lock_guard<std::mutex> lock(m_mutex);
      m_plcList = plcList;
      // if (m_sensorDataList.count(sensorKey.str()) > 0) {
      //   m_sensorDataList[sensorKey.str()].resetplc();
      // }

      // leftSize = recvSize - framelen;
      // memcpy(leftData, recvData + framelen, leftSize);

      return 0;
    }
  }

  return -1;
}

int32_t SensorProtoManager::DeSerializeRawData(uint8_t *recvData,
                                               const int32_t recvSize,
                                               uint8_t *leftData,
                                               int32_t &leftSize,
                                               const std::string &dstMccAddr,
                                               std::string &retsensorKey) {
  //找到完整的一帧数据
  for (int32_t index = 0; index < recvSize; index++) {
    if (recvData[index] == 0xa5 && recvData[index + 1] == 0x5a) {
      RawHead *head = reinterpret_cast<RawHead *>(recvData + index);
      int32_t framelen =
          index + sizeof(RawHead) + (head->rawDatalen * sizeof(float));
      if (framelen > recvSize) {
        Common_Log_e("rawdata framelen:%d recvSize:%d\n", framelen, recvSize);
        return -1;
      }

      if (head->mccAddr != stoi(dstMccAddr)) {
        return -2;
      }

      std::stringstream sensorKey;
      sensorKey << std::hex << head->taskId << head->mccAddr;
      std::vector<std::map<int32_t, rawData>> rawDataList;
      int32_t enablenum = 0;
      int bitnum = 0;
      while (bitnum < RAWDATA_CHAN_NUM) {
        if ((head->ch) & (0x1 << bitnum)) {
          enablenum++;
          m_sensorDataList[sensorKey.str()].sensorChan |= (0x1 << bitnum);
        }
        bitnum++;
      }

      uint32_t rawdatalen = head->rawDatalen * enablenum;
      int32_t listSize = (rawdatalen) / (enablenum * RAW_TYPE_NUM * DATA_WIDTH);
      if (listSize == 0) {
        Common_Log_e("listSize is 0");
        return -3;
      }
      rawDataList.resize(listSize);

      for (int32_t rawIndex = 0;
           rawIndex < listSize * (enablenum * RAW_TYPE_NUM * DATA_WIDTH);
           rawIndex += DATA_WIDTH) {
        int32_t cirtimes = rawIndex / (enablenum * RAW_TYPE_NUM * DATA_WIDTH);
        int32_t cirIndex = rawIndex % (enablenum * RAW_TYPE_NUM * DATA_WIDTH);
        int32_t typeIndex = cirIndex / (RAW_TYPE_NUM * DATA_WIDTH);
        int32_t chanIndex =
            (cirIndex % (RAW_TYPE_NUM * DATA_WIDTH)) / DATA_WIDTH;

        std::map<int32_t, rawData> &OnceRawData = rawDataList[cirtimes];
        float rawValue = *((float *)(recvData + index + sizeof(RawHead) +
                                     rawIndex * sizeof(float)));
        SetRawData(chanIndex, OnceRawData[typeIndex], ConvertEndium(rawValue));
      }

      std::lock_guard<std::mutex> lock(m_mutex);
      if (m_sensorDataList.count(sensorKey.str()) > 0) {
        m_sensorDataList[sensorKey.str()].resetraw();
      }
      m_sensorDataList[sensorKey.str()].channum = enablenum;
      m_sensorDataList[sensorKey.str()].chanparam = head->ch;
      m_sensorDataList[sensorKey.str()].timems = head->timems;
      m_sensorDataList[sensorKey.str()].addr = head->mccAddr;
      m_sensorDataList[sensorKey.str()].dataId = head->dataId;
      m_sensorDataList[sensorKey.str()].hatId = head->hatId;
      m_sensorDataList[sensorKey.str()].taskId = head->taskId;
      m_sensorDataList[sensorKey.str()].deviceId = head->deviceId;
      m_sensorDataList[sensorKey.str()].sn = head->mccAddr;
      m_sensorDataList[sensorKey.str()].rawDataList = rawDataList;
      m_sensorDataList[sensorKey.str()].plcDataList = m_plcList;

      // leftSize = recvSize - framelen;
      // memcpy(leftData, recvData + framelen, leftSize);
      retsensorKey = sensorKey.str();

      return 0;
    }
  }

  return -1;
}

int32_t SensorProtoManager::DeSerializeFigureData(uint8_t *recvData,
                                                  const int32_t recvSize,
                                                  uint8_t *leftData,
                                                  int32_t &leftSize,
                                                  const std::string &dstMccAddr,
                                                  std::string &retsensorKey) {
  //找到完整的一帧数据
  for (int32_t index = 0; index < recvSize; index++) {
    if (recvData[index] == 0xa5 && recvData[index + 1] == 0x5a) {
      SensorHead *head = reinterpret_cast<SensorHead *>(recvData + index);
      int32_t framelen =
          index + sizeof(SensorHead) + (head->rawDatalen + FIGURE_TYPE_NUM)*sizeof(float);
      if (framelen > recvSize) {
        // Common_Log_e("fig framelen:%d recvSize:%d\n", framelen, recvSize);
        // return -1;
        head->rawDatalen = ((recvSize - index - sizeof(SensorHead)) / sizeof(float)) - FIGURE_TYPE_NUM;
        framelen = index + sizeof(SensorHead) + (head->rawDatalen + FIGURE_TYPE_NUM)*sizeof(float);
      }

      if (head->mccAddr != stoi(dstMccAddr)) {
        return -2;
      }

      std::vector<std::map<int32_t, figureData>> figureDataList;
      std::vector<std::map<int32_t, rawData>> rawDataList;
      int32_t rawDataSize = (head->rawDatalen) /
                         (RAW_TYPE_NUM * DATA_WIDTH);
      // std::unique_lock<std::mutex> lock(m_mutex);
      std::stringstream sensorKey;
      sensorKey << std::hex << head->taskId << head->mccAddr;
      if (m_sensorDataList.count(sensorKey.str()) > 0) {
        figureDataList = m_sensorDataList[sensorKey.str()].figureDataList;
        rawDataList = m_sensorDataList[sensorKey.str()].rawDataList;
      } else {
        figureDataList.resize(1);
        rawDataList.resize(1);  // 只保留最新的数据
        // rawDataList.resize(rawDataSize);
      }
      // lock.unlock();

      int32_t typeIndex = GetFigDataType(head->axis, head->data_type);
      if (typeIndex < 0) {
        Common_Log_e("axis:%x data_type:%x is invalid", head->axis, head->data_type);
        return -2;
      }

      uint8_t sensorChan = 0;
      if (GetSensorChan(head->axis, sensorChan) < 0) {
        Common_Log_e("axis:%x is invalid", head->axis);
        return -2;
      }

      // 解析figuredata
      for (int32_t figureIndex = 0;
           figureIndex < figureDataList.size() * (FIGURE_TYPE_NUM * DATA_WIDTH);
           figureIndex += DATA_WIDTH) {
        int32_t cirtimes =
            figureIndex / (FIGURE_TYPE_NUM * DATA_WIDTH);
        int32_t cirIndex =
            figureIndex % (FIGURE_TYPE_NUM * DATA_WIDTH);
        int32_t chanIndex =
            (cirIndex % (FIGURE_TYPE_NUM * DATA_WIDTH)) / DATA_WIDTH;

        std::map<int32_t, figureData> &OncefigureData =
            figureDataList[cirtimes];
        float figvalue = *((float *)(recvData + index + sizeof(SensorHead) +
                                     figureIndex * sizeof(float)));
        SetFigureData(chanIndex, OncefigureData[typeIndex],
                      ConvertEndium(figvalue));
      }

      //解析rawdata
      std::map<int32_t, rawData> &OnceRawData = rawDataList[0];
      OnceRawData[typeIndex].rawValue.clear();
      uint32_t rawdatalen = head->rawDatalen;
      for (int32_t rawIndex = 0; rawIndex < rawDataSize * (RAW_TYPE_NUM * DATA_WIDTH);
           rawIndex += DATA_WIDTH) {
        int32_t cirIndex = rawIndex % (RAW_TYPE_NUM * DATA_WIDTH);
        int32_t chanIndex =
            (cirIndex % (RAW_TYPE_NUM * DATA_WIDTH)) / DATA_WIDTH;
        float rawValue = *((float *)(recvData + framelen - rawdatalen*sizeof(float) +
                                     rawIndex * sizeof(float)));
        SetRawData(chanIndex, OnceRawData[typeIndex], ConvertEndium(rawValue));
      }

      std::unique_lock<std::mutex> lockend(m_mutex);
      m_sensorDataList[sensorKey.str()].sensorChan |= (0x1 << sensorChan);
      if (head->timems > m_sensorDataList[sensorKey.str()].timems) {
        m_sensorDataList[sensorKey.str()].timems = head->timems;
      }
      m_sensorDataList[sensorKey.str()].addr = head->mccAddr;
      m_sensorDataList[sensorKey.str()].dataId = head->dataId;
      m_sensorDataList[sensorKey.str()].hatId = head->hatId;
      m_sensorDataList[sensorKey.str()].taskId = head->taskId;
      m_sensorDataList[sensorKey.str()].deviceId = head->deviceId;
      m_sensorDataList[sensorKey.str()].sn = head->mccAddr;
      m_sensorDataList[sensorKey.str()].figureDataList = figureDataList;
      m_sensorDataList[sensorKey.str()].rawDataList = rawDataList;
      m_sensorDataList[sensorKey.str()].plcDataList = m_plcList;
      lockend.unlock();

      // leftSize = recvSize - framelen;
      // memcpy(leftData, recvData + framelen, leftSize);
      retsensorKey = sensorKey.str();

      return 0;
    }
  }

  return -1;
}

int32_t SensorProtoManager::GetSensorData(std::string sensorKey, SensorData &sensorData) {
  if (m_sensorDataList.count(sensorKey) == 0) {
    return -1;
  } else if (m_sensorDataList[sensorKey].timems <= m_sensorDataList[sensorKey].lastuptimems + 20) {
    return -2;
  }
  std::lock_guard<std::mutex> lock(m_mutex);
  m_sensorDataList[sensorKey].lastuptimems = m_sensorDataList[sensorKey].timems;
  sensorData = m_sensorDataList[sensorKey];
  return 0;
}
